#include "../Biz/WWBizUtility.h"
#include "../Core/msgbus_interface.h"
#include "../Core/threadpool.h"
#include "../Core/CommonUtility.hpp"
#include "../Core/xparam.hpp"
#include "../Core/NetMsgBusHelper.hpp"
#include "../Biz/LoginMsgHandler.hpp"
#include "BizUIMsgTransfer.h"
#include "../Core/condition.hpp"
#include "../Biz/ConfigurationMgr.hpp"
#include "../Core/SimpleLogger.h"

#include <iostream>
#include <stdio.h>
#include <errno.h>
#include <arpa/inet.h>
#include <signal.h>

using namespace NetMsgBus;
using namespace wwbiz;
using namespace core;

using namespace std;

static LoggerCategory g_log("AliIM");

static sigset_t maskset;

class Cleaner
{
public:
    ~Cleaner()
    {
        MsgHandlerMgr::DropAllInstance();
        NetMsgBusDisConnect();
        DestroyMsgBus();
        threadpool::destroy_thread_pool();
        printf("AliIM Main Quit!\n");
    }
};

static void* sig_thread(void *arg)
{
    sigset_t *set = (sigset_t *)arg;
    int s,sig;
    for(;;){
        g_log.Log(lv_debug, "waiting signal...");
        s = sigwait(set, &sig);
        if(s != 0)
        {
            g_log.Log(lv_error, "sigwait signal error.");
            exit(1);
        }
        g_log.Log(lv_debug, "got signal : %d.", sig);
        switch(sig)
        {
        case SIGTERM:
        case SIGINT:
        case SIGQUIT:
            printf("quiting, please wait...\n");
            BizUIMsgTransfer::Instance()->StopIMReceiver();
            return 0;
            break;
        default:
            break;
        }
    }
}

void init_signals_env()
{
    //sigfillset(&maskset);
    sigemptyset(&maskset);
    //sigdelset(&maskset, SIGKILL);
    //sigdelset(&maskset, SIGSTOP);
    sigaddset(&maskset, SIGTERM);
    sigaddset(&maskset, SIGINT);
    sigaddset(&maskset, SIGQUIT);
    sigaddset(&maskset, SIGCHLD);

    int ret;
    ret = pthread_sigmask(SIG_BLOCK, &maskset, NULL);

    if(ret != 0)
    {
        g_log.Log(lv_error, "pthread_sigmask set error.");
        exit(1);
    }

    pthread_t thread;
    ret = pthread_create(&thread, NULL, &sig_thread, (void*)&maskset);
    if(ret != 0)
    {
        g_log.Log(lv_error, "create signal handler thread failed.");
        exit(1);
    }

}

static int StartReceiverFunc(unsigned short wwmain_port)
{
    if(wwmain_port == 0)
        wwmain_port = 19101;

    RegisterReceiverHandlerPtr sp_receiver_handler;
    MsgHandlerMgr::CreateInstance(sp_receiver_handler);

    std::string uniquestr = CommonUtility::GenerateGuidStr();
    std::string wwmain_name = "IMMainBiz" + uniquestr;
    if( 0 != NetMsgBusRegReceiver(wwmain_name, "", wwmain_port))
    {
        printf("register receiver client error.\n");
        return -1;
    }
    // make sure register is success return
    if(!sp_receiver_handler->WaitForRsp())
    {
        printf("register wwmain failed, quit.\n");
        return -1;
    }

    BizUIMsgTransferPtr sp_msg_transfer = BizUIMsgTransfer::Instance();
    sp_msg_transfer->Init(wwmain_name);

    LoginMsgHandlerPtr sp_login_handler;
    MsgHandlerMgr::CreateInstance(sp_login_handler);
    sp_msg_transfer->StartIMReceiver();


    sp_msg_transfer->WaitIMReceiverQuit();
    sp_login_handler->RemoveAllHandlers();
    sp_msg_transfer->RemoveAllHandlers();

    return 0;
}

int main()
{
    init_signals_env();

    // read global configuration
    bool ret = ConfigurationMgr::Instance().LoadConfig();
    if(!ret)
    {
        printf("read configuration error, aliww start failed.\n");
        return -1;
    }

    int server_port = 19000;
    int wwmain_port = 19101;
    IMGet_CommonConfig("serverport", server_port);
    IMGet_CommonConfig("wwmainport", wwmain_port);

    char strserverport[10] = {0};
    snprintf(strserverport, 10, "%d", server_port);
    pid_t msgbus_server_pid = fork();
    if(msgbus_server_pid == 0)
    {// start the netmsgbus server process.
        int ret = execlp(std::string(utility::GetModulePath() + "/msgbus_server").c_str(), "msgbus_server", strserverport, NULL);
        if(ret == -1)
        {
            perror("execute the msgbus_server process failed.");
            return -1;
        }
        // never be here
        assert(0);
    }
    // below is in main process.
    //
    Cleaner cleaner_;

    threadpool::init_thread_pool();

    // init the logger.
    int loglevel = lv_warn;
    IMGet_CommonConfig("loglevel", loglevel);
    SimpleLogger::Instance().Init(utility::GetModulePath() + "/log.log", (LogLevel)loglevel);

    InitMsgBus(0);
    sleep(1);
    int retry = 3;
    while(0 != NetMsgBusConnectServer("127.0.0.1", server_port))
    {
        if(retry-- < 0)
        {
            printf("connect msgbus server error, aliim will quit.\n");
            return -1;
        }
        sleep(2);
    }

    std::cout << " >> Mac/Linux AliWangWang << " << std::endl;

    StartReceiverFunc(wwmain_port);

    return 0;
}
